#pragma once


#include<iostream>
#include<queue>
#include<pthread.h>


namespace BlockQueueModule
{
    static const int grep=10;
    template<typename T>
    class BlockQueue
    {
        private:
        //判断是否达到最大容量
        bool IsFull()
        {
            return _q.size()==_cap;
        }
        //判断是否为空
        bool IsEmpty()
        {
            return _q.empty();
        }
    public:
        BlockQueue(int cap=grep):_cap(cap),_consumer_number(0),_productor_number(0)
        {
            pthread_cond_init(&_productor_cond,nullptr);
            pthread_cond_init(&_consumer_cond,nullptr);
            pthread_mutex_init(&_mutex,nullptr);
        }
        //生产者接口
        void EQueue(T& in)
        {
            pthread_mutex_lock(&_mutex);

            while(IsFull())//对条件进行判断,为了防止伪唤醒,我们通常使用while进行判断!
            {
                //达到最大容量，让生产者等待
                 std::cout << "生产者进入等待..." << std::endl;
                _productor_number++;
                pthread_cond_wait(&_productor_cond,&_mutex);
                _productor_number--;
                std::cout << "生产者被唤醒..." << std::endl;
            }
            _q.push(in);
            if(_consumer_number>0)
            {
                std::cout << "叫醒消费者" << std::endl;
                pthread_cond_signal(&_consumer_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        //消费者接口
        void Pop(T& out)
        {
            pthread_mutex_lock(&_mutex);
            while(IsEmpty())//对条件进行判断，为了防止伪唤醒，我们通常使用while进行判断！
            {
                //当没有时让消费者等待
                 std::cout << "消费者进入等待..." << std::endl;
                _consumer_number++;
                pthread_cond_wait(&_consumer_cond,&_mutex);
                _consumer_number--;
                 std::cout << "消费者被唤醒..." << std::endl;
            }

            out=_q.front();
            _q.pop();
            if(_productor_number>0)
            {
                 std::cout << "叫醒生产者" << std::endl;
                pthread_cond_signal(&_productor_cond);
            }

            pthread_mutex_unlock(&_mutex);
        }
        ~BlockQueue()
        {
            pthread_cond_destroy(&_productor_cond);
            pthread_cond_destroy(&_consumer_cond);
            pthread_mutex_destroy(&_mutex);
        }
    private:
        std::queue<T> _q; //保存数据的容器 临界资源
        int _cap; // bq最大容量
        pthread_mutex_t _mutex; //互斥
        pthread_cond_t _productor_cond; //生产者条件变量
        pthread_cond_t _consumer_cond; //消费者条件变量

        int _productor_number;
        int _consumer_number;
    };
}

